/*MyPhotoIndex Free Photo Organizer <www.myphotoindex.com>
  Copyright (C) <2006-2009>  <Asaf Yarkoni asaf@yarkoni.net>

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.*/
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Web;
using System.Globalization;

namespace MyPhotoIndex.Plugins.WebCommunity
{
    class RequestBuilder : Dictionary<String, String>
    {
        public event EventHandler<ProgressEventArgs> BlobReadProgressEvent;
        private string m_blobName;
        private Stream m_blobStream;
        private string m_blobContentType;
        private String m_method;
        private Dictionary<String, String> m_nonHashedValues = new Dictionary<string, string>();

        public RequestBuilder(String method)
        {
            m_method = method;
        }

        private void InitializeFormRequest(HttpWebRequest request)
        {
            StringBuilder requestBuilder = new StringBuilder(512);
            foreach (KeyValuePair<string, string> param in this)
            {
                if (requestBuilder.Length != 0)
                {
                    requestBuilder.Append("&");
                }

                requestBuilder.Append(param.Key);
                requestBuilder.Append("=");
                requestBuilder.Append(HttpUtility.UrlEncode(param.Value));
            }

            byte[] requestBytes = Encoding.UTF8.GetBytes(requestBuilder.ToString());

            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = requestBytes.Length;

            using (Stream requestStream = request.GetRequestStream())
            {
                requestStream.Write(requestBytes, 0, requestBytes.Length);
            }
        }

        private void InitializeMultiPartRequest(HttpWebRequest request)
        {
            string boundary = new Guid().ToString("D");

            StringBuilder headerBuilder = new StringBuilder(1024);
            foreach (KeyValuePair<string, string> param in this)
            {
                headerBuilder.Append("--");
                headerBuilder.Append(boundary);
                headerBuilder.Append("\r\n");
                headerBuilder.Append("Content-Disposition: form-data; name=\"");
                headerBuilder.Append(param.Key);
                headerBuilder.Append("\"\r\n\r\n");
                headerBuilder.Append(param.Value);
                headerBuilder.Append("\r\n");
            }

            foreach (KeyValuePair<string, string> param in m_nonHashedValues)
            {
                headerBuilder.Append("--");
                headerBuilder.Append(boundary);
                headerBuilder.Append("\r\n");
                headerBuilder.Append("Content-Disposition: form-data; name=\"");
                headerBuilder.Append(param.Key);
                headerBuilder.Append("\"\r\n\r\n");
                headerBuilder.Append(param.Value);
                headerBuilder.Append("\r\n");
            }

            headerBuilder.Append("--");
            headerBuilder.Append(boundary);
            headerBuilder.Append("\r\n");
            headerBuilder.Append("Content-Disposition: form-data; name=\"photo\"; filename=\"");
            headerBuilder.Append(m_blobName);
            headerBuilder.Append("\"\r\n");
            headerBuilder.Append("Content-Type: ");
            headerBuilder.Append(m_blobContentType);
            headerBuilder.Append("\r\n\r\n");

            string header = headerBuilder.ToString();
            string footer = "\r\n--" + boundary;

            byte[] headerBytes = Encoding.UTF8.GetBytes(header);
            byte[] footerBytes = Encoding.UTF8.GetBytes(footer);

            request.ContentType = "multipart/form-data; boundary=" + boundary;
            int totalBytes = headerBytes.Length + (int)m_blobStream.Length + footerBytes.Length;
            request.ContentLength = totalBytes;

            using (Stream requestStream = request.GetRequestStream())
            {
                requestStream.Write(headerBytes, 0, headerBytes.Length);

                byte[] buffer = new byte[1024];
                int bytesRead = 0;

                while ((bytesRead = m_blobStream.Read(buffer, 0, 1024)) != 0)
                {
                    requestStream.Write(buffer, 0, bytesRead);
                    if (BlobReadProgressEvent != null)
                    {
                        BlobReadProgressEvent.Invoke(this, new ProgressEventArgs(totalBytes, bytesRead));
                    }
                }

                requestStream.Write(footerBytes, 0, footerBytes.Length);
            }
        }

        internal void InitializeRequest(HttpWebRequest request)
        {
            SetRequestMetadata();

            request.Method = "POST";
            if (m_blobName == null)
            {
                InitializeFormRequest(request);
            }
            else
            {
                InitializeMultiPartRequest(request);
            }
        }

        internal void SetBlobParameter(string blobName, Stream blobStream, string blobContentType)
        {
            m_blobName = blobName;
            m_blobStream = blobStream;
            m_blobContentType = blobContentType;
        }

        private void SetRequestMetadata()
        {
                this["method"] = m_method;
        }
    }
}
